package mosquito.g7.blobs;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JFrame;
import javax.swing.JPanel;

import org.apache.log4j.Logger;

import mosquito.g7.StaticZap;
import mosquito.sim.Board;

public class BlobCreator {
	
	private static final Logger logger = Logger.getLogger(BlobCreator.class);
	private Set<Line2D> walls;
	private Set<Line2D> extensions;
	private Set<Line2D> fullWalls;
	
	private HashMap<Point2D, Line2D> map;
	
	public BlobCreator(Set<Line2D> walls) {
		this.walls = walls;
		
	}
	
	public void createBlobs(){
		extendLines();
		findBlobs();
		findConnectivity();
		displayLines();
	}
	
	private void extendLines() {
		extensions = new HashSet<Line2D>();
		fullWalls = new HashSet<Line2D>();
		map = new  HashMap<Point2D, Line2D>();
		walls.add(new Line2D.Double(StaticZap.MIN_X, StaticZap.MIN_Y, StaticZap.MIN_X, StaticZap.MAX_Y));
		walls.add(new Line2D.Double(StaticZap.MIN_X, StaticZap.MIN_Y, StaticZap.MAX_X, StaticZap.MIN_Y));
		walls.add(new Line2D.Double(StaticZap.MAX_X, StaticZap.MIN_Y, StaticZap.MAX_X, StaticZap.MAX_Y));
		walls.add(new Line2D.Double(StaticZap.MIN_X, StaticZap.MAX_Y, StaticZap.MAX_X, StaticZap.MAX_Y));
        
		Line2D tmpWall;
		Line2D[] lines = new Line2D[walls.size()];
		lines = walls.toArray(lines);
		double min1 = -1;
		double min2 = -1;
		Point2D p1 = null;
		Point2D p2 = null;
		double tmp1;
		double tmp2;
		for(int i = 0; i < lines.length && !map.containsKey(lines[i]); i++){
			min1 = -1;
			min2 = -1;
			for(int j = 0; j<lines.length && j!= i; j++){
				tmp1 = lines[i].getP1().distance(lines[j].getP1());
				tmp2 = lines[i].getP1().distance(lines[j].getP2());
				if(min1 == -1 || tmp1 < min1 || tmp2 < min1){
					min1 = (tmp1 < tmp2) ? tmp1 : tmp2;
					p1 = (tmp1 < tmp2) ? lines[j].getP1() : lines[j].getP2();
				}
				
				tmp1 = lines[i].getP2().distance(lines[j].getP2());
				tmp2 = lines[i].getP2().distance(lines[j].getP1());
				if(min2 == -1 || tmp1 < min2 || tmp2 < min2)
					min1 = (tmp1 < tmp2) ? tmp1 : tmp2;
					p2 = (tmp1 < tmp2) ? lines[j].getP1() : lines[j].getP2();
					
			}
			Line2D extend = new Line2D.Double(lines[i].getP1(), p1);
			extensions.add(extend);
			map.put(p2, extend);
			
			extend = new Line2D.Double(lines[i].getP2(), p2);
			extensions.add(extend);
			map.put(p2, extend);
			
		}
			/*
		for(Line2D wall : walls){
			tmpWall = findClosestLineToPoint(wall.getP1(), fullWalls);
			extendLineToWall(wall, tmpWall, 1);
			tmpWall = findClosestLineToPoint(wall.getP2(), fullWalls);
			extendLineToWall(wall, tmpWall, 2);
			fullWalls.add(wall);
		}*/
		
	}
	

	public Line2D findClosestLineToPoint(Point2D point, Set<Line2D> walls) {
		Line2D closest = null;
		double distance = -1;
		double tmpDist;
		for (Line2D wall : walls) {

			tmpDist = wall.ptLineDistSq(point);
		
			if (distance == -1) {
				closest = wall;
				distance = tmpDist;
			} else if (tmpDist < distance) {
				closest = wall;
				distance = tmpDist;

			}
			
		}
		
		logger.debug("closest wall "+ distance);
		return closest;
	}


	private Point2D getIntersection(double slope, Point2D point, Line2D wall) {

		double m1 = slope;
		double m2 = getSlope(wall);
		// lines are parallel
		if (m1 == m2)
			return null;
		double b1 = (point.getY() - m1 * point.getX());
		double b2 = (wall.getY1() - m2 * wall.getX1());
		logger.debug("m1 and m2" + m1 + " or " + m2);
		double x = (b2 - b1) / (m1 - m2);
		double y = m2 * x + b2;
		logger.debug("point "+ point.getX() + ", " + point.getY());
		logger.debug("intersect "+ x + ", " + y);
		return new Point2D.Double(x, y);
		
	

	}

	private double getSlope(Line2D wall) {
		double x;
		if(wall.getX1() - wall.getX2() == 0)
			x = 1;
		else
			x = (wall.getY1() - wall.getY2()) / (wall.getX1() - wall.getX2());
		logger.debug("slope "+ x);
		return x;

	}

	private void extendLineToWall(Line2D line, Line2D wall, int lineEnd) {

		double slope = -1/getSlope(wall);
		if (slope == 0)
			slope = 1;
		if(slope == -1 || slope == 1)
			slope = 0;
		Point2D point = lineEnd == 1 ? line.getP1() : line.getP2();
		logger.debug("Point ln distance : " +wall.ptLineDist(point));
		Point2D intersection = getIntersection(slope, point, wall);

		extensions.add(new Line2D.Double(point, intersection));
		fullWalls.add(new Line2D.Double(point, intersection));
		
		
	}

	private void findConnectivity() {
		// TODO Auto-generated method stub
		
	}

	private void findBlobs() {
		// TODO Auto-generated method stub
		
	}
	
	private void displayLines(){

		JFrame f = new JFrame();
		JPanel p = new LinePanel();
		f.setContentPane(p);

		int screenWidth = (int)Board.toScreenSpace(100);
		f.setSize(screenWidth, screenWidth);
		f.setVisible(true);
	}

	class LinePanel extends JPanel {
	    
	    @Override
	    public void paintComponent(Graphics g) {
	        super.paintComponent(g);
	        Graphics2D g2D = (Graphics2D) g;
	        g2D.setColor(Color.black);
	        int x = 0;
			if (walls != null)
				for (Line2D line : walls) {
					g2D.setColor(new Color(0, x+=5, x));
					Line2D trans = new Line2D.Double(Board.toScreenSpace(line
							.getP1()), Board.toScreenSpace(line.getP2()));
					g2D.draw(trans);
				}
			g2D.setColor(Color.red);
			if (extensions != null)
				for (Line2D line : extensions) {
					Line2D trans = new Line2D.Double(Board.toScreenSpace(line
							.getP1()), Board.toScreenSpace(line.getP2()));
					g2D.draw(trans);
				}
		//	g2D.drawString("HEYYY", 100, 100);
	    }
	}

}

